package com.framework.util.weixin.pay;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.Random;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;

import javax.net.ssl.SSLContext;
import javax.servlet.http.HttpServletRequest;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.jsoup.Jsoup;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.biz.model.Hmodel.sys.TSysLog;
import com.biz.model.common.SessionInfo;
import com.biz.utils.ConfigUtil;
import com.framework.dao.hdao.BaseDaoI;
import com.framework.util.Const;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;
import com.thoughtworks.xstream.io.xml.XmlFriendlyNameCoder;

import net.sf.json.JSONObject;

/**
 * 微信调起支付类
 * @author GengLong
 *
 */
public class WXRefund
{
	private static Logger logger = LoggerFactory.getLogger(WXRefund.class);

	private static String refund_url = "https://api.mch.weixin.qq.com/secapi/pay/refund";
	private static String Queryrefund_url = "https://api.mch.weixin.qq.com/pay/refundquery";
	private String appid;//微信分配的公众账号ID
	private String mch_id;//微信支付分配的商户号
	//private String sub_appid;//非必须 微信分配的子商户公众账号ID
	private String sub_mch_id;//微信支付分配的子商户号
	private String nonce_str;//随机字符串，不长于32位
	private String sign;//签名
	private String transaction_id;//微信订单号
	private String out_trade_no;//商户系统内部的订单号,transaction_id、out_trade_no二选一，如果同时存在优先级：transaction_id> out_trade_no
	private String out_refund_no;//商户系统内部的退款单号，商户系统内部唯一，同一退款单号多次请求只退一笔
	private int total_fee;//订单总金额，单位为分，只能为整数
	private int refund_fee;//退款总金额，订单总金额，单位为分，只能为整数
	private String op_user_id;//操作员帐号, 默认为商户号
	private String partnerKey;
	
	//表示请求器是否已经做了初始化工作
    private boolean hasInit = false;
  //HTTP请求器
    private CloseableHttpClient closeableHttpClient;
    @Autowired
	private BaseDaoI<TSysLog> sysLogDao;
	
	
    /**
     * 提交退款申请
     * @return
     * @throws Exception
     */
	public Map<String,Object> submitXmlToRefund() throws Exception
	{
		// 创建HttpClientBuilder
		HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
		// HttpClient
		 if (!hasInit) {
	            init();
	     }
		
		HttpPost httpPost = new HttpPost(refund_url);
		String xml = getPackage();
		StringEntity entity;
		String return_code = null;
		String return_msg = null;
		String result_code = null;
		String out_refund_no = null;
		String refund_id = null;
		String refund_channel = null;//ORIGINAL—原路退款 BALANCE—退回到余额
		String cash_refund_fee = null;
		String err_code_des = null;
		Map<String,Object> result_map = new HashMap<String, Object>();
		try
		{
			entity = new StringEntity(xml, "utf-8");
			httpPost.setEntity(entity);
			HttpResponse httpResponse;
			// post请求
			httpResponse = closeableHttpClient.execute(httpPost);
			HttpEntity httpEntity = httpResponse.getEntity();
			if (httpEntity != null)
			{
				// 打印响应内容
				String result = EntityUtils.toString(httpEntity, "UTF-8");
				logger.info(result);
				// 过滤
				result = result.replaceAll("<![CDATA[|]]>", "");
				return_code = Jsoup.parse(result).select("return_code").html();
				return_msg = Jsoup.parse(result).select("return_msg").html();
				if(return_code.equals("SUCCESS")){
					result_code = Jsoup.parse(result).select("result_code").html();
					out_refund_no = Jsoup.parse(result).select("out_refund_no").html();
					refund_id = Jsoup.parse(result).select("refund_id").html();
					refund_channel = Jsoup.parse(result).select("refund_channel").html();
					cash_refund_fee = Jsoup.parse(result).select("cash_refund_fee").html();
					if(result_code.equals("FAIL")){
						err_code_des = Jsoup.parse(result).select("err_code_des").html();
					}
				}
				
				result_map.put("return_code",return_code);
				result_map.put("return_msg",return_msg);
				result_map.put("result_code",result_code);
				result_map.put("out_trade_no",out_trade_no);
				result_map.put("out_refund_no",out_refund_no);
				result_map.put("refund_id",refund_id);
				result_map.put("refund_channel",refund_channel);
				result_map.put("cash_refund_fee",cash_refund_fee);
				result_map.put("err_code_des",err_code_des);
				
			}
			// 释放资源
			closeableHttpClient.close();
		} catch (Exception e)
		{
			logger.error("",e);
		}
		return result_map;
	}
	
	private void init() throws Exception{
		//指定读取证书格式为PKCS12
		KeyStore keyStore = KeyStore.getInstance("PKCS12");
		//读取本机存放的PKCS12证书文件
		FileInputStream instream = new FileInputStream(new File(ConfigUtil.get("cert_path")));
		try {
		//指定PKCS12的密码(商户ID)
		keyStore.load(instream, Const.CERT_PASSWORD.toCharArray());
		} finally {
		instream.close();
		}
		SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, Const.CERT_PASSWORD.toCharArray()).build();
		//指定TLS版本
		SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
		sslcontext,new String[] { "TLSv1" },null,
		SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
		//设置httpclient的SSLSocketFactory
		closeableHttpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
	}
	
	public String getPackage()
	{
		TreeMap<String, Object> treeMap = new TreeMap<String, Object>();
		treeMap.put("appid", this.appid);
		treeMap.put("mch_id", this.mch_id);
		//treeMap.put("sub_appid", this.sub_appid);
		treeMap.put("nonce_str", this.nonce_str);
		treeMap.put("op_user_id", this.op_user_id);
		treeMap.put("out_trade_no", this.out_trade_no);
		treeMap.put("out_refund_no", this.out_refund_no);
		//treeMap.put("transaction_id", this.transaction_id);
		treeMap.put("refund_fee", this.refund_fee);
		treeMap.put("sub_mch_id", this.sub_mch_id);
		treeMap.put("total_fee", this.total_fee);
		
		 ArrayList<String> list = new ArrayList<String>();
	        for(Map.Entry<String,Object> entry:treeMap.entrySet()){
	            if(entry.getValue()!=""){
	                list.add(entry.getKey() + "=" + entry.getValue() + "&");
	            }
	        }
	        int size = list.size();
	        String [] arrayToSort = list.toArray(new String[size]);
	        Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
	        StringBuilder sb = new StringBuilder();
	        for(int i = 0; i < size; i ++) {
	            sb.append(arrayToSort[i]);
	        }
		
		sb.append("key=" + partnerKey);
		logger.info(sb.toString());
		sign = MD5Util.MD5Encode(sb.toString()).toUpperCase();
		treeMap.put("sign",sign);
        
		StringBuilder xml = new StringBuilder();
		xml.append("<xml>\n");
		for (Entry<String, Object> entry : treeMap.entrySet())
		{
			if ("body".equals(entry.getKey()) || "sign".equals(entry.getKey()))
			{
				xml.append("<" + entry.getKey() + "><![CDATA[")
						.append(entry.getValue())
						.append("]]></" + entry.getKey() + ">\n");
			} else
			{
				xml.append("<" + entry.getKey() + ">").append(entry.getValue())
						.append("</" + entry.getKey() + ">\n");
			}
		}
		//xml.append("<sign>").append(sign).append("</sign>\n");
		xml.append("</xml>");
		logger.info(xml.toString());
		return xml.toString();
	}
	
	
//	public queryRefundByIds(String refund_id,String out_refund_no,String out_trade_no,String transaction_id){
//		
//	}
	
	public static String getRefund_url() {
		return refund_url;
	}


	public static void setRefund_url(String refund_url) {
		WXRefund.refund_url = refund_url;
	}


	public String getAppid() {
		return appid;
	}


	public void setAppid(String appid) {
		this.appid = appid;
	}


	public String getMch_id() {
		return mch_id;
	}


	public void setMch_id(String mch_id) {
		this.mch_id = mch_id;
	}


//	public String getSub_appid() {
//		return sub_appid;
//	}
//
//
//	public void setSub_appid(String sub_appid) {
//		this.sub_appid = sub_appid;
//	}


	public String getSub_mch_id() {
		return sub_mch_id;
	}


	public void setSub_mch_id(String sub_mch_id) {
		this.sub_mch_id = sub_mch_id;
	}


	public String getNonce_str() {
		return nonce_str;
	}


	public void setNonce_str(String nonce_str) {
		this.nonce_str = nonce_str;
	}


	public String getSign() {
		return sign;
	}


	public void setSign(String sign) {
		this.sign = sign;
	}


	public String getTransaction_id() {
		return transaction_id;
	}


	public void setTransaction_id(String transaction_id) {
		this.transaction_id = transaction_id;
	}


	public String getOut_trade_no() {
		return out_trade_no;
	}


	public void setOut_trade_no(String out_trade_no) {
		this.out_trade_no = out_trade_no;
	}


	public String getOut_refund_no() {
		return out_refund_no;
	}


	public void setOut_refund_no(String out_refund_no) {
		this.out_refund_no = out_refund_no;
	}


	public int getTotal_fee() {
		return total_fee;
	}


	public void setTotal_fee(int total_fee) {
		this.total_fee = total_fee;
	}


	public int getRefund_fee() {
		return refund_fee;
	}


	public void setRefund_fee(int refund_fee) {
		this.refund_fee = refund_fee;
	}


	public String getOp_user_id() {
		return op_user_id;
	}


	public void setOp_user_id(String op_user_id) {
		this.op_user_id = op_user_id;
	}


	public String getPartnerKey() {
		return partnerKey;
	}


	public void setPartnerKey(String partnerKey) {
		this.partnerKey = partnerKey;
	}
	
}
